`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/07/06 10:45:00
// Design Name: 
// Module Name: alu
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module alu(
  input [31:0] op1,
  input [31:0] op2,
  input [31:0] control,
  output [31:0] result
);

    assign alu_add  = control[11];
    assign alu_sub  = control[10];
    assign alu_slt  = control[ 9];
    assign alu_sltu = control[ 8];
    assign alu_and  = control[ 7];
    assign alu_nor  = control[ 6];
    assign alu_or   = control[ 5];
    assign alu_xor  = control[ 4];
    assign alu_sll  = control[ 3];
    assign alu_srl  = control[ 2];
    assign alu_sra  = control[ 1];
    assign alu_lui  = control[ 0];
    
    // 存储结果
    wire [31:0] add_sub_result; // 加减法
    wire [31:0] slt_result;
    wire [31:0] sltu_result;
    wire [31:0] and_result;
    wire [31:0] nor_result;
    wire [31:0] or_result;
    wire [31:0] xor_result;
    wire [31:0] sll_result;
    wire [31:0] srl_result;
    wire [31:0] sra_result;
    wire [31:0] lui_result;    
    
    assign and_result = op1 & op2;
    assign or_result = op1 | op2;
    assign nor_result = ~or_result;
    assign xor_result = op1 ^ op2;
    assign lui_result = {op2[15:0], 16'd0};

    
    // 调用加法器模块，计算：add、sub、slt、sltu
    
    // 1. 声名变量
    wire [31:0] adder_op1;
    wire [31:0] adder_op2;
    wire adder_cin;
    wire [31:0] adder_result;
    wire adder_cout;
    
    // 2. 赋值
    assign adder_op1 = op1;
    assign adder_op2 = alu_add ? op2 : ~op2;
    assign adder_cin = ~alu_add;
    
    // 3. 调用
    adder adder_module(
        .op1 (adder_op1),
        .op2 (adder_op2),
        .cin (adder_cin),
        .result (adder_result),
        .cout (adder_cout)
    );
    
    // 加减法结果
    assign add_sub_result = adder_result;
    
    // slt结果
    assign slt_result[31:1] = 31'd0;
    assign slt_result[0] = (op1[31] & ~op2[31]) |
                     (~(op1[31] ^ op2[31]) & adder_result[31]);
    
    // sltu结果
    assign sltu_result = {31'd0, ~adder_cout};
    
    // 移位
    wire [4:0] sa;  // 移位只有5位数
    assign sa = op1[4:0];
    wire [1:0] sa_1_0;
    wire [1:0] sa_3_2;
    assign sa_1_0 = sa[1:0];
    assign sa_3_2 = sa[3:2];
    
    // 逻辑左移
    wire [31:0] sll_1;
    wire [31:0] sll_2;
    assign sll_1 = {32{sa_1_0 == 2'b00}} & op2  // 00不移位
            | {32{sa_1_0 == 2'b01}} & {op2[30:0], 1'd0}  // 移1位：取低31位，拼上一个0
            | {32{sa_1_0 == 2'b10}} & {op2[29:0], 2'd0}
            | {32{sa_1_0 == 2'b11}} & {op2[28:0], 3'd0};
    assign sll_2 = {32{sa_3_2 == 2'b00}} & sll_1
            | {32{sa_3_2 == 2'b01}} & {sll_1[27:0], 4'd0}
            | {32{sa_3_2 == 2'b10}} & {sll_1[23:0], 8'd0}
            | {32{sa_3_2 == 2'b11}} & {sll_1[19:0], 12'd0};
    assign sll_result = sa[4] ? {sll_2[15:0],16'd0} : sll_2;
    
    // 逻辑右移
    wire [31:0] srl_1;
    wire [31:0] srl_2;
    assign srl_1 = {32{sa_1_0 == 2'b00}} & op2  // 00不移位
            | {32{sa_1_0 == 2'b01}} & {1'd0, op2[31:1]}     // 取高31位，高位补0
            | {32{sa_1_0 == 2'b10}} & {2'd0, op2[31:2]}
            | {32{sa_1_0 == 2'b11}} & {3'd0, op2[31:3]};
    assign srl_2 = {32{sa_3_2 == 2'b00}} & srl_1
            | {32{sa_3_2 == 2'b01}} & {4'd0, srl_1[31:4]}
            | {32{sa_3_2 == 2'b10}} & {8'd0, srl_1[31:8]}
            | {32{sa_3_2 == 2'b11}} & {12'd0, srl_1[31:12]};
    assign srl_result = sa[4] ? {16'd0, srl_2[31:16]} : srl_2;
    
    // 算术右移
    wire [31:0] sra_1;
    wire [31:0] sra_2;
    assign sra_1 = {32{sa_1_0 == 2'b00}} & op2  // 不移位
            | {32{sa_1_0 == 2'b01}} & {op2[31], op2[31:1]}  // 高位补符号位
            | {32{sa_1_0 == 2'b10}} & {{2{op2[31]}}, op2[31:2]}
            | {32{sa_1_0 == 2'b11}} & {{3{op2[31]}}, op2[31:3]};
    assign sra_2 = {32{sa_3_2 == 2'b00}} & sra_1
            | {32{sa_3_2 == 2'b01}} & {{4{sra_1[31]}}, sra_1[31:4]}
            | {32{sa_3_2 == 2'b10}} & {{8{sra_1[31]}}, sra_1[31:8]}
            | {32{sa_3_2 == 2'b11}} & {{12{sra_1[31]}}, sra_1[31:12]};
    assign sra_result = sa[4] ? {{16{sra_2[31]}}, sra_2[31:16]} : sra_2;
    
    
    // 输出
    assign result = (alu_add | alu_sub) ? add_sub_result[31:0]
            : alu_slt  ?  slt_result
            : alu_sltu ?  sltu_result
            : alu_add  ?  and_result
            : alu_nor  ?  nor_result
            : alu_or   ?  or_result
            : alu_xor  ?  xor_result
            : alu_sll  ?  sll_result
            : alu_srl  ?  srl_result
            : alu_sra  ?  sra_result
            : alu_lui  ?  lui_result
            : 32'd0;
    
endmodule